package pjn;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class CharactersFinder {

    private Splitter splitter = new Splitter();
    private GramaticalResolver gramaticalResolver = new GramaticalResolver();

    public Set<Character> findCharacters(List<String> sentences, Map<Integer, Set<Integer>> charactersInSentencesCount,
            Map<Character, Map<Character, MultiWordCharacterHelper>> charactersPairs) {
        Set<Character> characters = new HashSet<Character>();

        for (int i = 0; i < sentences.size(); i++) {
            Set<Character> charactersInThisSentence = new HashSet<Character>();
            boolean previousWasCharacter = false;
            boolean oneBeforeLastWasCharacter = false;
            Character previousCharacter = null;
            String previousWord = null;
            String oneBeforeLastWord = null;

            String sentence = sentences.get(i);

            for (String word : splitter.splitIntoWords(sentence)) {
                if (isCharacter(word)) {
                    boolean alreadyAdded = false;
                    for (Character character : characters) {
                        if (character.isItThisCharacter(word)) {
                            character.addName(word);
                            character.addNameOccurenceSentence(word, i);

                            if (previousWasCharacter
                                    && (oneBeforeLastWord == null || (!gramaticalResolver.isItParticiple(oneBeforeLastWord)
                                            && !gramaticalResolver.isItGenitive(oneBeforeLastWord) && !KnowledgeBase.PREPOSITIONS.contains(oneBeforeLastWord)))) {
                                addCharactersPair(charactersPairs, previousCharacter, previousWord, character, word, i);
                            }

                            alreadyAdded = true;
                            previousCharacter = character;
                            charactersInThisSentence.add(character);
                            break;
                        }
                    }
                    if (!alreadyAdded) {
                        Character character = new Character(word);
                        character.addNameOccurenceSentence(word, i);
                        characters.add(character);

                        if (previousWasCharacter
                                && (oneBeforeLastWord == null || (!gramaticalResolver.isItParticiple(oneBeforeLastWord)
                                        && !gramaticalResolver.isItGenitive(oneBeforeLastWord) && !KnowledgeBase.PREPOSITIONS.contains(oneBeforeLastWord)))) {
                            addCharactersPair(charactersPairs, previousCharacter, previousWord, character, word, i);
                        }
                        previousCharacter = character;
                        charactersInThisSentence.add(character);
                    }

                    previousWasCharacter = true;
                } else {
                    if (!oneBeforeLastWasCharacter && previousWasCharacter) {
                        previousCharacter.setStandsAlone(true);
                    }
                    if (previousWasCharacter) {
                        oneBeforeLastWasCharacter = true;
                    } else {
                        oneBeforeLastWasCharacter = false;
                    }
                    previousWasCharacter = false;
                    previousCharacter = null;
                }
                oneBeforeLastWord = previousWord;
                previousWord = word;
            }

            int charactersCount = charactersInThisSentence.size();
            if (charactersInSentencesCount.get(charactersCount) == null) {
                charactersInSentencesCount.put(charactersCount, new HashSet<Integer>());
            }
            charactersInSentencesCount.get(charactersCount).add(i);

        }

        return characters;
    }

    public void findMultiWordCharacters(Set<Character> characters, Map<Character, Map<Character, MultiWordCharacterHelper>> charactersPairs) {
        Set<Character> processed = new HashSet<Character>();
        String character1Name;
        String character2Name;

        for (Character character1 : charactersPairs.keySet()) {
            Map<Character, MultiWordCharacterHelper> character1Pairs = charactersPairs.get(character1);

            if (character1Pairs.size() == 1) {
                Character character2 = character1Pairs.keySet().toArray(new Character[0])[0];
                if (charactersPairs.get(character2).size() == 1) { //wystepuja tylko razem lub ewentualnie samodzielnie

                    if (!processed.contains(character1) && !processed.contains(character2)
                            && (character1.getGender() == null || character2.getGender() == null || character1.getGender() == character2.getGender())) {

                        MultiWordCharacterHelper helper = character1Pairs.get(character2);
                        for (String name : helper.getMultiWordNames()) {
                            String[] splitted = name.split(" ");
                            if (helper.isCorrectOrder(name)) {
                                character1Name = splitted[0];
                                character2Name = splitted[1];
                            } else {
                                character1Name = splitted[1];
                                character2Name = splitted[0];
                            }

                            Set<Integer> occurences = helper.getNamesOccurenceSentences().get(name);
                            character1.getNamesOccurenceSentences().get(character1Name).removeAll(occurences);
                            character1.setTotalOccurrenceCount(character1.getTotalOccurrenceCount() - occurences.size());
                            if (character1.getNamesOccurenceSentences().get(character1Name).isEmpty()) {
                                character1.getNamesOccurenceSentences().remove(character1Name);
                                character1.getNames().remove(character1Name);
                            }
                            character2.getNamesOccurenceSentences().get(character2Name).removeAll(occurences);
                            character2.setTotalOccurrenceCount(character2.getTotalOccurrenceCount() - occurences.size());
                            if (character2.getNamesOccurenceSentences().get(character2Name).isEmpty()) {
                                character2.getNamesOccurenceSentences().remove(character2Name);
                                character2.getNames().remove(character2Name);
                            }

                            character1.addName(name);
                            character1.addNameOccurenceSentences(name, occurences);
                        }
                        for (String name : character2.getNames()) {
                            character1.addName(name);
                            character1.addNameOccurenceSentences(name, character2.getNamesOccurenceSentences().get(name));
                        }
                        if (character2.getGender() != null) {
                            character1.setGender(character2.getGender());
                        }

                        characters.remove(character2);
                    }
                    processed.add(character1);
                    processed.add(character2);
                }
            } else { //character1 jest wspolny dla wielu
                boolean canAdd = true;
                for (Character key : character1Pairs.keySet()) {
                    if (charactersPairs.get(key).size() > 1) { //wiele kolizji
                        canAdd = false;
                    }
                }

                if (canAdd) {
                    for (Character character2 : character1Pairs.keySet()) {
                        MultiWordCharacterHelper helper = character1Pairs.get(character2);
                        for (String name : helper.getMultiWordNames()) {
                            String[] splitted = name.split(" ");
                            if (helper.isCorrectOrder(name)) {
                                character1Name = splitted[0];
                                character2Name = splitted[1];
                            } else {
                                character1Name = splitted[1];
                                character2Name = splitted[0];
                            }

                            Set<Integer> occurences = helper.getNamesOccurenceSentences().get(name);
                            if (character1.getNamesOccurenceSentences().get(character1Name) != null) {
                                character1.getNamesOccurenceSentences().get(character1Name).removeAll(occurences);
                                character1.setTotalOccurrenceCount(character1.getTotalOccurrenceCount() - occurences.size());
                                if (character1.getNamesOccurenceSentences().get(character1Name).isEmpty()) {
                                    character1.getNamesOccurenceSentences().remove(character1Name);
                                    character1.getNames().remove(character1Name);
                                }
                            }
                            if (character2.getNamesOccurenceSentences().get(character2Name) != null) {
                                character2.getNamesOccurenceSentences().get(character2Name).removeAll(occurences);
                                character2.setTotalOccurrenceCount(character2.getTotalOccurrenceCount() - occurences.size());
                                if (character2.getNamesOccurenceSentences().get(character2Name).isEmpty()) {
                                    character2.getNamesOccurenceSentences().remove(character2Name);
                                    character2.getNames().remove(character2Name);
                                }
                            }

                            character2.addName(name);
                            character2.addNameOccurenceSentences(name, occurences);
                        }
                    }

                    if (!character1.isStandsAlone()) {
                        characters.remove(character1);
                    }
                }
            }
        }
    }

    public void findAliasses(Set<Character> characters, List<String> sentences, Map<Integer, Set<Integer>> charactersInSentencesCount) {

    }

    private void addCharactersPair(Map<Character, Map<Character, MultiWordCharacterHelper>> charactersPairs, Character character1, String character1Name,
            Character character2, String character2Name, Integer sentenceNumber) {

        Map<Character, MultiWordCharacterHelper> character1Pairs = charactersPairs.get(character1);
        Map<Character, MultiWordCharacterHelper> character2Pairs = charactersPairs.get(character2);

        if (character1Pairs == null) {
            character1Pairs = new HashMap<Character, MultiWordCharacterHelper>();
            charactersPairs.put(character1, character1Pairs);
        }
        if (character2Pairs == null) {
            character2Pairs = new HashMap<Character, MultiWordCharacterHelper>();
            charactersPairs.put(character2, character2Pairs);
        }

        String name = character1Name + " " + character2Name;
        if (character1Pairs.containsKey(character2) && character2Pairs.containsKey(character1)) {
            character1Pairs.get(character2).addMultiWordName(name);
            character1Pairs.get(character2).addNameOccurenceSentence(name, sentenceNumber);
            character1Pairs.get(character2).addCorrectOrder(name, true);

            character2Pairs.get(character1).addMultiWordName(name);
            character2Pairs.get(character1).addNameOccurenceSentence(name, sentenceNumber);
            character2Pairs.get(character1).addCorrectOrder(name, false);
        } else {
            character1Pairs.put(character2, new MultiWordCharacterHelper(name, sentenceNumber, true));
            character2Pairs.put(character1, new MultiWordCharacterHelper(name, sentenceNumber, false));
        }
    }

    private boolean isCharacter(String word) {
        int[] ids = JCLP.rec(word);
        if (ids.length == 0 && word.length() > 2 && java.lang.Character.isUpperCase(word.charAt(0))) { //mozliwy bohater
            if (!KnowledgeBase.INVENTED_NAMES.contains(word)) { //sprawdzenie czy nie jest to nazwa wlasna (np. nazwa geograficzna)
                return true;
            }
        }

        return false;
    }

}
